﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace TD.bom
{
    /// <summary>
    /// Gère le déplacement d'un objet mobile en 2 dimensions
    /// </summary>
    public class _2dAcceleratedObject
    {
        protected Point m_position;
        protected Point m_speed;
        protected Point m_perTickAcceleration;
        
        protected uint m_lastTick; // Nombre de "tick" à la dernière mise à jour

        MapObjectPosition Position
        {
            get
            {
                return new MapObjectPosition() { X = (int)m_position.X, Y = (int)m_position.Y };
            }
        }

        /// <summary>
        /// Construit un objet mobile à partir d'une origine, un vecteur vitesse 
        /// initiale et un vecteur acceleration
        /// </summary>
        /// <param name="p_position">Position initiale de l'objet</param>
        /// <param name="p_initialSpeed">Vecteur vitesse initiale en pixel / s</param>
        /// <param name="p_acceleration">Vecteur acceleration initiale en pixel / s²</param>
        public _2dAcceleratedObject(MapObjectPosition p_position, Point p_initialSpeed, Point p_acceleration)
        {
            // Origine
            m_position = new Point(p_position.X, p_position.Y);

            // Vecteur vitesse
            m_speed = p_initialSpeed;
            
            // Vecteur acceleration converti en pixel / ms
            m_perTickAcceleration.X = p_acceleration.X / 1000d;
            m_perTickAcceleration.Y = p_acceleration.Y / 1000d;

            // On réinitialise le chrono
            m_lastTick = Game.Instance.Clock.Time;
        }

        /// <summary>
        /// Construit un objet mobile à partir d'une origine, une destination, une vitesse 
        /// initiale et un vecteur acceleration
        /// </summary>
        /// <param name="p_position">Position initiale de l'objet</param>
        /// <param name="p_position">Destination de l'objet</param>
        /// <param name="p_initialSpeed">Vitesse initiale en pixel / s</param>
        /// <param name="p_acceleration">Vecteur acceleration initiale en pixel / s²</param>
        public _2dAcceleratedObject(MapObjectPosition p_position, MapObjectPosition p_destination, 
            double p_initialSpeed, Point p_acceleration)
        {
            // Intégrité des paramètres
            if (p_position.X == p_destination.X && p_position.Y == p_destination.Y)
            {
                throw new ArgumentException("La position et la destination doivent être différents pour construire un _2dAcceleratedObject");
            }

            // Origine
            m_position = new Point(p_position.X, p_position.Y);

            // Le reste
            GoTo(p_destination, p_initialSpeed, p_acceleration);
        }

        /// <summary>
        /// Reparamètre l'objet de manière à atteindre la destination spécifiée avec 
        /// la vitesse et l'accélération spécifiées.
        /// </summary>
        /// <param name="p_destination">Destination de l'objet</param>
        /// <param name="p_initialSpeed">Vitesse initiale en pixel / s</param>
        /// <param name="p_acceleration">Vecteur acceleration initiale en pixel / s²</param>
        public void GoTo(MapObjectPosition p_destination, double p_initialSpeed, Point p_acceleration)
        {
            // Vecteur vitesse
            m_speed.X = (p_initialSpeed * (p_destination.X - m_position.X)) / p_destination.GetDistanceXYFrom(m_position);
            m_speed.Y = (p_initialSpeed * (p_destination.Y - m_position.Y)) / p_destination.GetDistanceXYFrom(m_position);

            // Vecteur acceleration converti en pixel / ms
            m_perTickAcceleration.X = p_acceleration.X / 1000d;
            m_perTickAcceleration.Y = p_acceleration.Y / 1000d;

            // On réinitialise le chrono
            m_lastTick = Game.Instance.Clock.Time;
        }

        /// <summary>
        /// Obtient la position mise à jour
        /// </summary>
        /// <returns>Une instance de MapObjectPosition indiquant la position mise à jour</returns>
        public MapObjectPosition GetNextPosition()
        {
            // Calcul du temps écoulé depuis la dernière mise à jour
            uint l_thisTick = Game.Instance.Clock.Time;
            uint l_delta = l_thisTick - m_lastTick;
            
            m_lastTick = l_thisTick;

            // Mise à jour de la vitesse
            m_speed.X += l_delta * m_perTickAcceleration.X;
            m_speed.Y += l_delta * m_perTickAcceleration.Y;

            // Mise à jour de la position
            m_position.X += (l_delta * m_speed.X) / 1000d;
            m_position.Y += (l_delta * m_speed.Y) / 1000d;

            return Position;
        }
    }
}
